package team.nmsg.ge.system.init.shiro;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMethod;

import com.alibaba.fastjson.JSONObject;

import team.nmsg.ge.system.AppServerConstant;
import team.nmsg.ge.system.bean.AppToken;
import team.nmsg.ge.system.controller.BaseController;
import team.nmsg.ge.system.exception.NMSIllegalOperationException;
import team.nmsg.ge.system.exception.NMSTokenCantRefreshException;
import team.nmsg.ge.system.exception.NMSTokenExpireException;
import team.nmsg.ge.system.init.websocket.SysMsgPusher;
import team.nmsg.ge.system.service.IAuthenticationService;
import team.nmsg.ge.system.util.SysSpringContext;



/**
 * 访问控制过滤器
 *
 */
public class StatelessAccessControlFilter extends AccessControlFilter {
	
	private static Logger logger =  LoggerFactory.getLogger( StatelessAccessControlFilter.class );
	
	
//	@Autowired
	private IAuthenticationService authenticationServiceImpl;
	
	/**
	 * 先执行：isAccessAllowed 再执行onAccessDenied
	 *
	 * isAccessAllowed：表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，
	 * 如果允许访问返回true，否则false；
	 *
	 * 如果返回true的话，就直接返回交给下一个filter进行处理。 如果返回false的话，回往下执行onAccessDenied
	 */
	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
		return false;
	}
 
	/**
	 * onAccessDenied：表示当访问拒绝时是否已经处理了；如果返回true表示需要继续处理；
	 * 如果返回false表示该拦截器实例已经处理了，将直接返回即可。
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		
		//从客户端传递过来的信息中获取按token-key获取到token， 如果包含token，则校验token的合法性，如果不包含，则说明是没有登录，提示客户端进行登录
		HttpServletRequest req = (HttpServletRequest) request;
		String clientToken = "";
		
		try {
			
			if(isOptionsReq(req)){
				return true;
			}
			clientToken = BaseController.getTokenStrFromReq(req);
			SysMsgPusher.getMsgPusher().sendtoUser("I accept your request!", clientToken);
			SysMsgPusher.getMsgPusher().sendtoAll("I accept a request!");
			//校验token
			if( authenticationServiceImpl == null ){
				authenticationServiceImpl = SysSpringContext.getService(IAuthenticationService.class);
			}
			AppToken appToken = authenticationServiceImpl.checkClientTokenStr(clientToken);
			//委托给Realm进行登录
			getSubject(request, response).login(appToken);
		}catch (Exception e) {
			//token过期异常，同时客户端
			tokenCheckFailed(request, response, e);
			logger.error(e.getMessage() );
			return false;
		}
		return true;
	}
	public static boolean isOptionsReq(HttpServletRequest req){
		String method = req.getMethod();
		if(RequestMethod.OPTIONS.toString().equals(method)){
			return true;
		}
		return false;
	}

	// 登录失败时默认返回401状态码
	private void tokenCheckFailed(ServletRequest request, ServletResponse response , Exception e) throws IOException {
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
		JSONObject jsonObject = new JSONObject();
		if(e instanceof NMSIllegalOperationException){
			jsonObject.put(AppServerConstant.ERR_KEY_RELOGIN, true);
		}else if(e instanceof  NMSTokenExpireException){
			jsonObject.put(AppServerConstant.ERR_KEY_TOKENEXPIRT, true);
			
		}else if(e instanceof NMSTokenCantRefreshException){
			jsonObject.put(AppServerConstant.ERR_KEY_RELOGIN, true);
		}else{
			jsonObject.put(e.getMessage(), true);
		}
		httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", httpRequest.getMethod());
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
        httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));
		httpResponse.getWriter().write(jsonObject.toString());
	}
}
